home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -serious- / programming / basic / udp_chat / udp_chatv2.7.asc < prev    next >
Text File  |  2000-02-23  |  78KB  |  2,082 lines

  1. ;
  2. ;                      UDP Chat code V2.7   16/1/2000
  3. ;
  4. ;    This code sends and receives UDP data packets like a
  5. ;  a simple IRC client, and  checks wether they have arrived
  6. ;  at their destination, and allows other copies of this
  7. ;  program to log in to this one (can act as a server or client).
  8. ;
  9. ;  Written by Anton Reinauer <anton@ww.co.nz>.
  10. ;  GUI: Alvaro Thompson <alvaro@enterprise.net> - And awful hacks
  11. ;  by me to his nice font sensitive code :-)
  12. ;        - typical bloody games programmer ;-)
  13. ;
  14. ;  Thanks to Paul Burkey for TCP_Funcs and to Dr. Ercole Spiteri
  15. ;  for TCP-to-Blitz.
  16. ;
  17. ;  ARexx portname: "UDP_Chat"
  18. ;
  19. ;  Turn overflow errors off in Debugger options,
  20. ;  and have amigalibs.res resident in compiler options.
  21.  
  22. WBStartup
  23. NoCli
  24. DEFTYPE .w
  25. ResetTimer
  26.  
  27. ;****************************************************************
  28. ;****************           UDP Stuff              **************
  29. ;***********  Cut out all this and put it in your game **********
  30. ;****************************************************************
  31.  
  32. ;****************    UDP Variables and Constants   **************
  33.  
  34. hostname.s="localhost"  ; "localhost" default destination host address
  35. #NO_CONNECTION=1        ; 0 - are we connected, or have we been connected to the Internet since bootup?  1- No
  36. #COMMS_DEBUG=1          ; 1 - 1 for debug info and multiple local copies
  37. CNIF #COMMS_DEBUG=1
  38.   #TEST_TIME_SYNC=0     ; 1 to test time sync
  39. CEND
  40. #MESSAGE_ARRAY_SIZE=256 ; 256
  41. #INTERNAL_MESSAGE_SIZE=30  ;30
  42. GAME_NAME.s="UDP_Chat"  ; "UDP_Chat"  Game name (for login)
  43. max_wait=250            ; 250 Time to wait for an acknowledgement (frames)
  44. number_resends=5        ; 5 Number of resends to wait, before disconnecting player
  45. lag_allowance=5         ; 5 Number of frames to add to the current lag, when waiting for an out-of-order packet.
  46. max_number_players=8    ; 8
  47. #ACKNOWLEDGE_PACKET=3
  48. #OFFLINE=0
  49. #ONLINE=1
  50. #ATTEMPTING_TO_CONNECT=1
  51. #SERVER=2
  52. #CLIENT=3
  53.  
  54. #DISCONNECTED=1
  55. #CONNECTED=2
  56. #CONNECTION_REJECTED=3
  57. #START_GAME=4
  58. #NEW_PLAYER=5
  59. #SYSTEM_MESSAGE=4   ;  System message
  60. #HIGH=3             ;  High priority Security Message or Comms Debug info
  61. #MEDIUM=2           ;  Medium   "      "
  62. #LOW=1              ;  Low      "      "
  63. #SERVER_NUMBER=1
  64. #GAME_CLOSING_TIMEOUT=1500
  65. #DISCONNECT_TIMEOUT=1500
  66. #CLIENT_SERVER=0
  67. #PEER_TO_PEER=1
  68. #LOGIN_TIMEOUT=6000    ; 2 minutes- timeout for login attempt
  69. #SEND=0
  70. #RECEIVE=1
  71. #NUMBER_TIME_SYNCS=6    ; number of packets sent to sync time
  72. #MIN_NUMBER_OF_SYNCS=#NUMBER_TIME_SYNCS/2  ; minimum no of similar time syncs for correct time
  73. #SERVER_RESYNC=4
  74. #SYNC_ALLOWANCE=5       ; 5 frames- 100ms
  75. #TOTAL_PLAYER_INFOS=50
  76. #NUMBERB=1      ; player info types
  77. #NUMBERW=2
  78. #NUMBERL=3
  79. #STRING=4
  80. #FILENAME=5
  81. #MEMORY_BLOCK=6
  82. #END_OF_CRITICAL_DATA=7
  83. #PLAYER_INFO_BUFFER_SIZE=50
  84. #UNORDERED=0
  85. #ORDERED=1
  86. online=#OFFLINE
  87. my_number=0
  88. player_housekeeping=0
  89. sock.l=-1
  90. security_level=#LOW   ; level of security warnings (normally #LOW- show #LOW and higher ie: all)
  91. free_security_message=0
  92. next_security_message=0
  93. system_time.l=0
  94. drop_frame=0
  95. login_timeout=0
  96. time_sync=False
  97. current_synching_player=2
  98. current_synched_player=0
  99. CNIF #COMMS_DEBUG=1
  100.   comms_debug_level=#LOW  ; level of debug info (normally #LOW- show #LOW and higher ie: all)
  101.   free_debug_message=0
  102.   next_debug_message=0
  103. CEND
  104. tcp_stack=False
  105. disconnect_timeout=0
  106. mtu=1500
  107. player_info_buffer.l=0
  108. player_info_buffer_size.l=0
  109. new_player=0
  110. send_buffer.l=0
  111. incoming_game_data.l=0
  112. incoming_game_data_status=False
  113. socket_base.l=0
  114. CNIF #TEST_TIME_SYNC=1
  115.   temp_no=0
  116. CEND
  117.  
  118. ;***************************  UDP Dims  *************************
  119.  
  120. .Dims
  121.  
  122. INCLUDE "UDPHeader.bb2"  ;Standard TCP/UDP library structures and UDP Funcs Newtypes, and Net protocol constants
  123.  
  124. Dim messages.message_status(max_number_players,#MESSAGE_ARRAY_SIZE)
  125. Dim host.sockaddrin(max_number_players), hostlen.w(max_number_players)
  126. Dim players.player_info(max_number_players)
  127. Dim player_honesty(max_number_players,max_number_players)
  128. Dim last_message_number(max_number_players)
  129. Dim free_message(max_number_players)
  130. Dim packet_number.l(max_number_players)
  131. Dim reliable_packet_in.l(max_number_players)
  132. Dim unreliable_packet_out.l(max_number_players)
  133. Dim unreliable_packet_in.l(max_number_players)
  134. Dim comms_debug_message.system_message(#INTERNAL_MESSAGE_SIZE)
  135. Dim security_message.system_message(#INTERNAL_MESSAGE_SIZE)
  136. Dim login_stage(max_number_players)
  137. Dim time_syncs.sync(max_number_players)
  138. Dim player_info.info(#TOTAL_PLAYER_INFOS)
  139.  
  140. DEFTYPE .sockaddrin temphost
  141.  
  142. For a=1 To max_number_players      ; this array dimension is for the player number who is claiming another is offline
  143.   For b=1 To max_number_players    ; this dimension is for the player number who is claimed to be offline
  144.     player_honesty(a,b)=False      ; initialise array
  145.   Next
  146.   messages(a,0)\ack=True
  147.   unreliable_packet_in(a)=-1
  148. Next
  149.  
  150.  
  151. ;************************    UDP Funcs    ***********************
  152.  
  153. ;  These are all specific functions for your game to communicate
  154. ;  over the internet or by modem/null-modem.
  155.  
  156. .Security_Warning
  157. Statement Security_Warning{text$,level}
  158.   SHARED security_level    ; security_level= 0 none, 1 all warnings, 2 medium and severe warnings and 3 only severe warnings
  159.   SHARED security_message(),free_security_message
  160.  
  161.   If level>=security_level  ; only print out security_level warnings if at set security_level level or higher
  162.     If level<#SYSTEM_MESSAGE
  163.       text$="Warning: " + text$
  164.     EndIf
  165.     If free_security_message <= #INTERNAL_MESSAGE_SIZE  ;  if array not full
  166.       security_message(free_security_message)\message=text$,level  ; add debug message to array
  167.       free_security_message+1     ; up index pointer
  168.     Else
  169.       free_security_message+1
  170.     EndIf
  171.   EndIf
  172. End Statement
  173.  
  174. .Read_Security_Warning
  175. Function.s Read_Security_Warning{}
  176.   SHARED security_message(),free_security_message
  177.   SHARED next_security_message
  178.  
  179.   If next_security_message=free_security_message OR next_security_message>#INTERNAL_MESSAGE_SIZE
  180.     If free_security_message>#INTERNAL_MESSAGE_SIZE+1
  181.       next_security_message=0
  182.       free_security_message=0
  183.       lost_messages=free_security_message-#INTERNAL_MESSAGE_SIZE-1
  184.       Function Return "Warning: System message array full- have lost " + Str$(lost_messages) + " message(s)!"
  185.     Else
  186.       next_security_message=0
  187.       free_security_message=0
  188.       Function Return ""
  189.     EndIf
  190.   Else
  191.     next_security_message+1
  192.     Function Return security_message(next_security_message-1)\message
  193.   EndIf
  194. End Function
  195.  
  196. CNIF #COMMS_DEBUG=1
  197.   .Comms_Debug
  198.   Statement Comms_Debug{text$,level}
  199.     SHARED comms_debug_level  ; comms_debug= 0 none, 1 all info, 2 medium and high priority info and 3 only high priority info
  200.     SHARED comms_debug_message(),free_debug_message
  201.  
  202.     If level>=comms_debug_level   ; only print out debug info if at set debug level or higher
  203.       If free_debug_message < #INTERNAL_MESSAGE_SIZE  ;  if array not full
  204.         comms_debug_message(free_debug_message)\message=text$,level  ; add debug message to array
  205.         free_debug_message+1     ; up index pointer
  206.       Else
  207.         If free_debug_message=#INTERNAL_MESSAGE_SIZE   ; if array full- send error message
  208.           comms_debug_message(free_debug_message)\message="Comms debug message array full- may lose next message!",#HIGH
  209.           free_debug_message+1
  210.         EndIf
  211.       EndIf
  212.     EndIf
  213.   End Statement
  214.  
  215.   .Read_Comms_Debug_Messages
  216.   Function.s Read_Comms_Debug_Messages{}
  217.     SHARED comms_debug_message(),free_debug_message
  218.     SHARED next_debug_message
  219.  
  220.     If next_debug_message=free_debug_message OR next_debug_message>#INTERNAL_MESSAGE_SIZE
  221.       If free_debug_message>#INTERNAL_MESSAGE_SIZE+1
  222.         next_debug_message=0
  223.         free_debug_message=0
  224.         lost_messages=free_debug_message-#INTERNAL_MESSAGE_SIZE-1
  225.         Function Return "Warning: Comms debug message array full- have lost " + Str$(lost_messages) + " message(s)!"
  226.       Else
  227.         next_debug_message=0
  228.         free_debug_message=0
  229.         Function Return ""
  230.       EndIf
  231.     Else
  232.       next_debug_message+1
  233.       Function Return comms_debug_message(next_debug_message-1)\message
  234.     EndIf
  235.   End Function
  236. CEND
  237.  
  238. Function.b NewNTSC {}
  239.   lib$="graphics.library"
  240.   *gb.GfxBase=OpenLibrary_(&lib$,0)
  241.  
  242.   If *gb
  243.     If *gb\DisplayFlags AND #REALLY_PAL Then p.b=0 Else p=-1
  244.     CloseLibrary_ *gb
  245.   EndIf
  246.  
  247.   Function Return p
  248. End Function
  249.  
  250.  
  251. INCLUDE "UDPFuncs.bb2"        ; basic UDP socket functions
  252.  
  253. .Dim_Message_Arrays
  254. Function Dim_Message_Arrays{new_max_number_players}
  255.   SHARED online,max_number_players,messages()
  256.   SHARED host(),hostlen(),players(),player_honesty()
  257.   SHARED unreliable_packet_out.l(),unreliable_packet_in.l()
  258.   SHARED reliable_packet_in.l(),last_message_number()
  259.   SHARED free_message(),packet_number(),login_stage()
  260.   SHARED time_syncs(),player_info_buffer.l,player_info_buffer_size.l
  261.  
  262.   If online=#OFFLINE
  263.     max_number_players=new_max_number_players
  264.  
  265.     Dim messages.message_status(max_number_players,#MESSAGE_ARRAY_SIZE)
  266.     Dim host.sockaddrin(max_number_players), hostlen.w(max_number_players)
  267.     Dim players.player_info(max_number_players)
  268.     Dim player_honesty(max_number_players,max_number_players)
  269.     Dim last_message_number(max_number_players)
  270.     Dim free_message(max_number_players)
  271.     Dim packet_number.l(max_number_players)
  272.     Dim reliable_packet_in.l(max_number_players)
  273.     Dim unreliable_packet_out.l(max_number_players)
  274.     Dim unreliable_packet_in.l(max_number_players)
  275.     Dim login_stage(max_number_players)
  276.     Dim time_syncs.sync(max_number_players)
  277.  
  278.     For a=1 To max_number_players      ; this array dimension is for the player number who is claiming another is offline
  279.       For b=1 To max_number_players    ; this dimension is for the player number who is claimed to be offline
  280.         player_honesty(a,b)=False       ; initialise array
  281.       Next
  282.     messages(a,0)\ack=True
  283.     unreliable_packet_in(a)=-1
  284.     Next
  285.  
  286.     If player_info_buffer>0
  287.       a=FreeMem_(player_info_buffer,player_info_buffer_size)
  288.     EndIf
  289.  
  290.     player_info_buffer_size.l=(#PLAYER_INFO_BUFFER_SIZE) * max_number_players
  291.     player_info_buffer=AllocMem_(player_info_buffer_size,#MEMF_PUBLIC)
  292.     If player_info_buffer=0
  293.       Security_Warning{"Out of memory for Player Info Buffer",#SYSTEM_MESSAGE}
  294.       Function Return False
  295.     EndIf
  296.  
  297.   EndIf
  298.   Function Return True
  299. End Statement
  300.  
  301. .Get_Packet_Source            ; Check if packet has come from player already logged on.
  302. Function.w Get_Packet_Source{}
  303.   SHARED host(),temphost,max_number_players
  304.   i=0
  305.   exit=0
  306.   Repeat                    ; check for each player (hostname and socket)
  307.     i+1
  308.     If host(i)\sin_addr\s_addr=temphost\sin_addr\s_addr AND  host(i)\sin_port=temphost\sin_port
  309.       exit=1
  310.     EndIf
  311.     If i=max_number_players AND exit=0; if at end of players and no match is found
  312.       i=-1
  313.       exit=1
  314.     EndIf
  315.   Until  exit=1
  316.  
  317.   Function Return i
  318. End Function
  319.  
  320. .Get_Ascii_Address                     ; build a.b.c.d numerical address from long number
  321. Function.s Get_Ascii_Address{address.l}
  322.   string_address.l=Inet_NtoA{address} ; get memory address of ASCII string version of host address (a.b.c.d)
  323.   If string_address=0
  324.     Function Return ""
  325.   EndIf
  326.   Repeat                               ; build ASCII host string
  327.     letter.b=(Peek.b(string_address))
  328.     If letter<>0
  329.       temp$=temp$+Chr$(letter)
  330.     EndIf
  331.     string_address+1
  332.   Until letter=0
  333.   Function Return temp$
  334. End Function
  335.  
  336. .Send_Reliable_Message         ; this message is checked to see if it has arrived, and resent if not
  337. Statement Send_Reliable_Message{address.l,data_length.w,player,protocol,ordering}  ; if no confirmation can be made, link i
  338.  SHARED messages(),free_message(),packet_number(),system_time
  339.  
  340.   If protocol=#PEER_TO_PEER    ; Send message Peer-To-Peer
  341.     send_string.s=RSet$ ("",data_length + 4)
  342.     NPokeL &send_string.s,packet_number(player)
  343.     a=CopyMem_(address,&send_string.s + 4,data_length)
  344.     messages(player,free_message(player))\number=packet_number(player),False,system_time,send_string.s,0,player  ; log message
  345.                                                                                                            ; inmessage array
  346.     WriteUDP{&send_string.s,data_length + 4,player}   ; send message
  347.     packet_number(player)+1               ; set packet number to next free packet number (+1)
  348.     free_message(player)+1        ; set next free message to next one
  349.     messages(player,free_message(player))\ack=True  ; stop resends if all messages have been acknowledged
  350.     If free_message(player)=#MESSAGE_ARRAY_SIZE+1 Then free_message(player)=0    ; if packet number >#MESSAGE_ARRAY_SIZE then wr
  351.   Else     ; Send message Client-Server
  352.  
  353.   EndIf
  354.  
  355. End Statement
  356.  
  357. .Send_Unreliable_Message
  358. Statement Send_Unreliable_Message{address.l,data_length.w,player,protocol}
  359.   SHARED UNRELIABLE_PACKET.s,unreliable_packet_out(),send_buffer.l
  360.  
  361.   If protocol=#PEER_TO_PEER   ; Send message Peer-To-Peer
  362.     NPokeL send_buffer,unreliable_packet_out(player)
  363.     NPokeB send_buffer+4,$25  ;  UNRELIABLE_PACKET.s
  364.     a=CopyMem_(address,send_buffer + 5 ,data_length)
  365.  
  366.     unreliable_packet_out(player)+1
  367.     WriteUDP{send_buffer,data_length + 5,player}
  368.  
  369.   Else   ; Send message Client-Server
  370.  
  371.   EndIf
  372.  
  373. End Statement
  374.  
  375. Function New_Player_Info{player,address.l,port.w,start_of_info.l,player_info_length.l}
  376.   SHARED players(),player_info_buffer.l,host()
  377.   If address=0
  378.     address=NPeekL(start_of_info)
  379.     port=NPeekW(start_of_info + 4)
  380.     start_of_info=start_of_info + 6
  381.     info_size.l=player_info_length - 6
  382.   Else
  383.     info_size.l=player_info_length
  384.   EndIf
  385.  
  386.   If Get_Host_By_Address{&address,port,player}=True
  387.     ascii_address.s=Get_Ascii_Address{address}
  388.     players(player)\status=#ONLINE,ascii_address.s
  389.     players(player)\disconnect_requested=False
  390.  
  391.     player_info_start.l=player_info_buffer + (player-1) * #PLAYER_INFO_BUFFER_SIZE
  392.     If info_size <= #PLAYER_INFO_BUFFER_SIZE
  393.       NPokeL player_info_start,player_info_length  ; put length of player info into first 4 bytes of info
  394.       a=CopyMem_(start_of_info,player_info_start+4,player_info_length)                        ; buffer
  395.  
  396.     CNIF #COMMS_DEBUG=1
  397.      Else
  398.        Comms_Debug{"Player Info Buffer overflowed!!!",#HIGH}
  399.     CEND
  400.     EndIf
  401.  
  402.     text$="New player at- " + ascii_address.s + " Port: " + Str$(host(player)\sin_port)
  403.     Security_Warning{text$,#SYSTEM_MESSAGE}
  404.   Else
  405.     Security_Warning{"New player at unknown host!",#MEDIUM}
  406.     Function Return False
  407.   EndIf
  408.  
  409.   Function Return True
  410. End Statement
  411.  
  412. Function.s Get_My_Player_Info{my_number}
  413.   SHARED player_info(),mtu,host()
  414.  
  415.   i=0
  416.   packet_size=0
  417.   While player_info(i)\info_type>0 AND i<#TOTAL_PLAYER_INFOS AND player_info(i)\info_type<>#END_OF_CRITICAL_DATA
  418.     Select player_info(i)\info_type
  419.       Case #NUMBERB
  420.         packet_size+1
  421.         If packet_size < mtu
  422.           send$=send$ + Chr$(player_info(i)\numberb)
  423.         Else
  424.           CNIF #COMMS_DEBUG=1
  425.             Comms_Debug{"Player Info Packet too big!",#HIGH}
  426.           CEND
  427.           Function Return ""
  428.         EndIf
  429.  
  430.       Case #NUMBERW
  431.         packet_size+2
  432.         If packet_size < mtu
  433.           send$=send$ + Mki$(player_info(i)\numberw)
  434.         Else
  435.           CNIF #COMMS_DEBUG=1
  436.             Comms_Debug{"Player Info Packet too big!",#HIGH}
  437.           CEND
  438.           Function Return ""
  439.         EndIf
  440.  
  441.       Case #NUMBERL
  442.         packet_size+4
  443.         If packet_size < mtu
  444.           send$=send$ + Mkl$(player_info(i)\numberl)
  445.         Else
  446.           CNIF #COMMS_DEBUG=1
  447.             Comms_Debug{"Player Info Packet too big!",#HIGH}
  448.           CEND
  449.           Function Return ""
  450.         EndIf
  451.  
  452.       Case #STRING
  453.         string_length.w=Len(player_info(i)\string)
  454.         packet_size + string_length + 2
  455.         If packet_size < mtu
  456.           send$=send$ + Mki$(string_length) + player_info(i)\string
  457.         Else
  458.           CNIF #COMMS_DEBUG=1
  459.             Comms_Debug{"Player Info Packet too big!",#HIGH}
  460.           CEND
  461.           Function Return ""
  462.         EndIf
  463.  
  464.       Case #MEMORY_BLOCK
  465.         packet_size + 4 + player_info(i)\memory_length
  466.         If packet_size < mtu
  467.           send$=send$ + Mkl$(player_info(i)\memory_length)
  468.           For j=player_info(i)\memory_start To player_info(i)\memory_start + player_info(i)\memory_length
  469.             send$=send$ + Chr$(NPeekB(j))
  470.           Next
  471.         Else
  472.           CNIF #COMMS_DEBUG=1
  473.             Comms_Debug{"Player Info Packet too big!",#HIGH}
  474.           CEND
  475.           Function Return ""
  476.         EndIf
  477.  
  478.       Case #FILENAME
  479.  
  480.     End Select
  481.     i+1
  482.   Wend
  483.  
  484.   If New_Player_Info{my_number,host(0)\sin_addr\s_addr,host(0)\sin_port,&send$,packet_size}
  485.     Function Return send$
  486.   Else
  487.     Function Return ""
  488.   EndIf
  489. End Function
  490.  
  491. .Initialise_Server
  492. Function Initialise_Server{localport}
  493.   ; Set up the game so we can act as Server
  494.   SHARED online,port_used,my_number,players(),host()
  495.   SHARED max_number_players,player_info_buffer.l
  496.  
  497.   If online=#OFFLINE
  498.     If Initialise_UDP{localport}        ; bind socket to local port
  499.  
  500.       send$=Get_My_Player_Info{1}    ; get my player info from array
  501.       If send$<>""                        ; and save it to the player info
  502.         online=#SERVER                                                                  ; memory area
  503.         my_number=#SERVER_NUMBER
  504.         players(#SERVER_NUMBER)\status=#ONLINE     ; We are now online as Server
  505.         Function Return True
  506.       Else
  507.         Function Return False
  508.       EndIf
  509.     Else
  510.       Security_Warning{"Error in setting up UDP at Port "+ Str$(port_used),#SYSTEM_MESSAGE}
  511.     EndIf
  512.  
  513.   Else
  514.     Select online
  515.       Case #CLIENT
  516.         Security_Warning{"Already logged on to a Server!",#SYSTEM_MESSAGE}
  517.       Case #SERVER
  518.         Security_Warning{"Already acting as a Server!",#SYSTEM_MESSAGE}
  519.       Case #ATTEMPTING_TO_CONNECT
  520.         Security_Warning{"Already attempting to log on to a Server!",#SYSTEM_MESSAGE}
  521.     End Select
  522.   EndIf
  523.   Function Return False
  524. End Function
  525.  
  526. .Disconnect_From_Game
  527. Function Disconnect_From_Game{}
  528.   ; Remove us from the game, and if we're the Server- close down
  529.   ; the game and take away our ability to act as Server.
  530.   SHARED online,players(),max_number_players,my_number
  531.   SHARED disconnect_timeout,time_syncs(),login_stage()
  532.   SHARED CP_END_GAME.s,CP_REQ_PLAYER_DISCONNECT.s
  533.  
  534.   For i=0 To max_number_players
  535.     USEPATH time_syncs(i)
  536.     \player_synching=0
  537.     \current_sync=0
  538.     \average_ping=0
  539.     For j=0 To #NUMBER_TIME_SYNCS   ; clear time_sync array
  540.       time_syncs(i)\ping_start[j]=0
  541.       time_syncs(i)\ping_time[j]=0
  542.     Next
  543.     login_stage(i)=0  ; reset login stage array
  544.   Next
  545.  
  546.   Select online
  547.     Case #OFFLINE
  548.       Function Return True
  549.     Case #SERVER  ; if we are Server
  550.       dummy=0
  551.       For i=2 To max_number_players
  552.         If players(i)\status=#ONLINE  ; send to player if they're online
  553.           send$=CP_END_GAME.s
  554.           dummy=1
  555.           Send_Reliable_Message{&send$,Len(send$),i,#PEER_TO_PEER,#UNORDERED}   ; Send string to connected players
  556.         EndIf
  557.       Next
  558.       If dummy=1
  559.         Security_Warning{"Telling players Game has ended.",#SYSTEM_MESSAGE}
  560.         disconnect_timeout=#DISCONNECT_TIMEOUT
  561.         Function Return False
  562.       Else
  563.         online=#OFFLINE
  564.         Function Return True
  565.       EndIf
  566.     Case #CLIENT  ;  we are client
  567.       send$=CP_REQ_PLAYER_DISCONNECT.s + Mki$(my_number)
  568.       Send_Reliable_Message{&send$,Len(send$),#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED}
  569.       Security_Warning{"Telling Server we are disconnecting from Game.",#SYSTEM_MESSAGE}
  570.       disconnect_timeout=#DISCONNECT_TIMEOUT
  571.       Function Return False
  572.  
  573.     Case #ATTEMPTING_TO_CONNECT  ;  we are client
  574.       send$=CP_REQ_PLAYER_DISCONNECT.s + Mki$(my_number)
  575.       Send_Reliable_Message{&send$,Len(send$),#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED}
  576.       Security_Warning{"Telling Server we are disconnecting from Game.",#SYSTEM_MESSAGE}
  577.       disconnect_timeout=#DISCONNECT_TIMEOUT
  578.       Function Return False
  579.  
  580.    End Select
  581. End Function
  582.  
  583. .Connect_To_Server
  584. Function Connect_to_Server{host.s,port.w}
  585.   SHARED online, CP_REQ_CONNECT.s, GAME_NAME.s, NET_PROTOCOL_VERSION.s
  586.   SHARED login_timeout
  587.   If online=#OFFLINE
  588.     If Initialise_UDP{port}       ; bind socket to local port
  589.       If Get_Host_By_Name{GTGetString(0,51), GTGetInteger(0,52),1}=True
  590.         Security_Warning{"Attempting to connect to Server",#SYSTEM_MESSAGE}
  591.         send$=Mkl$(0) + CP_REQ_CONNECT.s + GAME_NAME.s + Chr$(0) + NET_PROTOCOL_VERSION.s  ; "0000" is a Pad for packet number
  592.         WriteUDP{&send$,Len(send$),1}   ; send connection request
  593.         login_timeout=#LOGIN_TIMEOUT
  594.         online=#ATTEMPTING_TO_CONNECT
  595.         Function Return True
  596.       Else
  597.         Function Return False
  598.       EndIf
  599.     Else
  600.       Function Return False
  601.     EndIf
  602.   Else
  603.     Select online
  604.       Case #CLIENT
  605.         Security_Warning{"Already logged on to a Server!",#SYSTEM_MESSAGE}
  606.       Case #SERVER
  607.         Security_Warning{"Already acting as a Server!",#SYSTEM_MESSAGE}
  608.       Case #ATTEMPTING_TO_CONNECT
  609.         Security_Warning{"Already attempting to log on to a Server!",#SYSTEM_MESSAGE}
  610.     End Select
  611.     Function Return False
  612.   EndIf
  613. End Function
  614.  
  615. .Find_Next_Message
  616. Statement Find_Next_Message{player}
  617.   SHARED last_message_number(),messages(),free_message()
  618.  
  619.   exit=0
  620.   Repeat              ; find next unacknowledged message in array
  621.  
  622.     last_message_number(player)+1
  623.     If last_message_number(player)=#MESSAGE_ARRAY_SIZE+1 Then last_message_number(player)=0
  624.  
  625.     If last_message_number(player)=free_message(player)  ; if have got to free_message then there are no messages waiting to be
  626.       exit=1
  627.     Else
  628.       If messages(player,last_message_number(player))\ack=False   ; we've found the next unacknowledged message in the array
  629.         exit=1
  630.       EndIf
  631.     EndIf
  632.  
  633.   Until exit=1
  634. End Statement
  635.  
  636. .Clear_Player_Arrays
  637. Statement Clear_Player_Arrays{player}    ; clear player's arrays
  638.   SHARED last_message_number(),messages(),free_message(),host()
  639.   SHARED player_honesty(),players(),max_number_players
  640.   SHARED unreliable_packet_out(),unreliable_packet_in()
  641.   SHARED packet_number(),login_stage()
  642.  
  643.   a=last_message_number(player)
  644.   Repeat                      ; clear message array
  645.     messages(player,a)\ack=True    ; clear unacknowledged messages off message array
  646.     If a=free_message(player) Then exit=True
  647.     a+1
  648.     If a=#MESSAGE_ARRAY_SIZE+1 Then a=0    ; if at end of array, jump to beginning
  649.   Until exit=True
  650.   last_message_number(player)=0
  651.   free_message(player)=0
  652.   packet_number(player)=0
  653.  
  654.   host(player)\sin_addr\s_addr=0   ; clear host address array
  655.   host(player)\sin_port=0
  656.  
  657.   For a= 1 To max_number_players   ; clear player_honesty array
  658.     player_honesty(player,a)=False  ; clear disconnected player's array
  659.     player_honesty(a,player)=False  ; clear other player's arrays who have claimed the disconnected player was offline
  660.   Next
  661.  
  662.   players(player)\disconnect_requested=False ; reset disconnect request item
  663.   players(player)\status=#OFFLINE      ; player's status is offline
  664.  
  665.   unreliable_packet_out(player)=0      ; set player's unreliable packet number back to zero
  666.   unreliable_packet_in(player)=-1
  667.   login_stage(player)=0
  668.  
  669. End Statement
  670.  
  671. .Disconnect_Player
  672. Statement Disconnect_Player{player}  ; Disconnect Player from game
  673.   SHARED players(),online,max_number_players
  674.   SHARED CP_REP_PLAYER_DISCONNECTED.s,CP_REQ_PLAYER_DISCONNECT.s
  675.  
  676.   If online=#SERVER   ;  If we are the Server
  677.     dummy=0
  678.     Security_Warning{"Player " +  Str$(player) + " has disconnected",#SYSTEM_MESSAGE}
  679.     For i=2 To max_number_players
  680.       If players(i)\status > #OFFLINE   ; send to all players if they're online
  681.         If i <> player ; check to see if any players are left online
  682.           dummy=1
  683.         EndIf
  684.         send$=CP_REP_PLAYER_DISCONNECTED.s + Mki$(player) ; tell other players
  685.         Send_Reliable_Message{&send$,Len(send$),i,#PEER_TO_PEER,#UNORDERED}   ; Send string to connected players that player is
  686.       EndIf
  687.     Next
  688.  
  689.     If dummy=0     ; if no players are left online
  690.       CNIF #COMMS_DEBUG=1
  691.         Comms_Debug{"All players have disconnected",#MEDIUM}
  692.       CEND
  693.     EndIf
  694.  
  695.     Clear_Player_Arrays{player}  ; clear message array of player's messages
  696.  
  697.   Else    ;  if we're a client, inform Server that a player can't be contacted
  698.     CNIF #COMMS_DEBUG=1
  699.       Comms_Debug{"Telling Server we can't contact player!",#MEDIUM}
  700.     CEND
  701.     send$=CP_REQ_PLAYER_DISCONNECT.s + Mki$(player)
  702.     Send_Reliable_Message{&send$,Len(send$),#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED}   ; Send string to Server
  703.   EndIf
  704.  
  705. End Statement
  706.  
  707. .Resend_Message       ; resend a message
  708. Statement Resend_Message{player,message_number}
  709.   SHARED messages(),number_resends,online,players()
  710.   SHARED max_number_players,system_time
  711.  
  712.   messages(player,message_number)\timestamp=system_time
  713.   messages(player,message_number)\resends+1
  714.   If messages(player,message_number)\resends>number_resends  ; is host not responding? After 5 retries consider link broken.
  715.      CNIF #COMMS_DEBUG=1
  716.        Comms_Debug{"Host not responding to Packet no: " + Str$(message_number),#HIGH}
  717.      CEND
  718.      If messages(player,message_number)\player<>#SERVER_NUMBER   ; We've lost contact with a Client
  719.  
  720.        If players(player)\disconnect_requested=False ; if haven't already sent a Disconnect req
  721.          Disconnect_Player{player}                   ; send disconnect request to Server
  722.          players(player)\disconnect_requested=True   ; don't send any more disconnect requests
  723.        EndIf                                                                       ; for that player
  724.      Else              ; we've lost contact with Server- game over!
  725.        online=#OFFLINE
  726.        For a= 1 To max_number_players
  727.          Clear_Player_Arrays{a}
  728.        Next
  729.      EndIf
  730.   Else
  731.      string_length=Len(messages(player,message_number)\message)
  732.  
  733.      WriteUDP{&messages(player,message_number)\message,string_length,player}
  734.      CNIF #COMMS_DEBUG=1
  735.        Comms_Debug{"Resent Packet no:" + Str$(message_number),#HIGH}
  736.      CEND
  737.   EndIf
  738. End Statement
  739.  
  740. .Acknowledge_Packet   ; mark message as been sucessfully sent
  741. Function Acknowledge_Packet{ack_packet_number,player}
  742.  
  743.   SHARED last_message_number(),free_message(),messages()
  744.   SHARED lag_allowance,players(),system_time
  745.  
  746.   a=last_message_number(player)
  747.   exit=-2
  748.   Repeat
  749.     If messages(player,a)\number=ack_packet_number   ; find message in sent messages array
  750.       messages(player,a)\ack=True         ; note it as being received
  751.       players(player)\lag=system_time-messages(player,a)\timestamp ; calculate lag
  752.       exit=True
  753.     Else
  754.       If a=free_message(player)  ; in case bad packet number sends it into a loop! It will only check around buffer once.
  755.         exit=False
  756.         a$="Warning- Invalid Packet number " + Str$(incoming_packet_number)
  757.         Security_Warning{ a$ + " from Player " + Str$(player),#MEDIUM}
  758.       EndIf
  759.       a+1
  760.     EndIf
  761.  
  762.     If a=#MESSAGE_ARRAY_SIZE+1 Then a=0    ; if at end of array, jump to beginning
  763.   Until exit>-2
  764.  
  765.   If exit=True     ; only do if packet has valid packet_number
  766.     If a=last_message_number(player) ; if last message unacknowle
  767.       Find_Next_Message{player}                                      ; is acknowledged then find next unacknowledged message
  768.     Else                ; we have lost a packet- resend last packet number!
  769.       allowable_lag=players(player)\lag + lag_allowance ; current lag of player
  770.       If messages(player,last_message_number)\timestamp-system_time > allowable_lag
  771.         text$="Received packet " + Str$(ack_packet_number) + " ACK out of order,from P: " + Str$(player)
  772.         Security_Warning{text$ + " resending last packet",#MEDIUM}      ; then resend last message
  773.         Resend_Message{player,last_message_number}  ; if run out of resends- disconnect player
  774.       Else
  775.         text$="Received packet " + Str$(ack_packet_number) + " ACK out of order,from P: " + Str$(player)
  776.         Security_Warning{text$ + "- no resend yet.",#MEDIUM}
  777.       EndIf
  778.     EndIf
  779.   EndIf
  780.   Function Return exit
  781. End Function
  782.  
  783. .Time_Sync             ; Sync time with Server/Sync clients time.
  784. Statement Time_Sync{mode,player,sync_reply_number,incoming_packet_number}
  785.   SHARED time_sync,time_syncs(),current_synching_player
  786.   SHARED max_number_players,system_time.l,players()
  787.   CNIF #TEST_TIME_SYNC=1
  788.     SHARED temp_no
  789.   CEND
  790.   SHARED CP_TIME_SYNC.s,CP_TIME_SYNC_ACK.s,CP_CALCULATED_TIME.s
  791.   SHARED CP_CALCULATED_TIME_ACK.s
  792.  
  793.   If time_sync<>#SERVER_RESYNC
  794.     If mode=#SEND
  795.       If time_sync=#SERVER
  796.  
  797.         current_synching_player+1
  798.         If current_synching_player > max_number_players
  799.           current_synching_player=2
  800.         EndIf
  801.  
  802.         USEPATH time_syncs(current_synching_player)
  803.         If \player_synching=True
  804.           If \current_sync <= #NUMBER_TIME_SYNCS
  805.             \ping_start[\current_sync]=system_time
  806.             number=\current_sync
  807.  
  808.             CNIF #TEST_TIME_SYNC=1
  809.               If temp_no<2
  810.                 If \current_sync=1 Then number=4
  811.                 If \current_sync=4
  812.                   number=1
  813.                   temp_no+1
  814.                 EndIf
  815.               EndIf
  816.             CEND
  817.  
  818.             send$=CP_TIME_SYNC.s + Mki$(number)
  819.             CNIF #COMMS_DEBUG=1
  820.               Comms_Debug{"Sending Time Sync to Player " + Str$(player) +"- number: "+ Str$(\current_sync),#LOW}
  821.             CEND
  822.             \current_sync+1
  823.             Send_Reliable_Message{&send$,Len(send$),current_synching_player,#PEER_TO_PEER,#UNORDERED}
  824.           Else
  825.             Statement Return
  826.           EndIf
  827.         Else
  828.           Statement Return
  829.         EndIf
  830.       Else
  831.  
  832.       EndIf
  833.     Else                     ; receive time syc or time sync ack
  834.       If time_sync=#SERVER   ; If Server
  835.         USEPATH time_syncs(player)
  836.         If sync_reply_number <= #NUMBER_TIME_SYNCS
  837.           If sync_reply_number=\last_in_order_ping_number
  838.             If sync_reply_number < #NUMBER_TIME_SYNCS
  839.               \last_in_order_ping_number+1
  840.             EndIf
  841.           Else
  842.             \waiting_for_restart=True
  843.             \sync_received[sync_reply_number]=True
  844.             CNIF #COMMS_DEBUG=1
  845.               Comms_Debug{"Out of order Time Sync to Player: " + Str$(player) + " Waiting for restart of Sync",#MEDIUM}
  846.             CEND
  847.           EndIf
  848.  
  849.           While \sync_received[\last_in_order_ping_number + 1]=True AND \last_in_order_ping_number < #NUMBER_TIME_SYNCS
  850.             \last_in_order_ping_number+1
  851.           Wend
  852.  
  853.           If \waiting_for_restart=False
  854.             ping.l=system_time -  \ping_start[sync_reply_number]
  855.             \ping_time[sync_reply_number]=ping
  856.             CNIF #COMMS_DEBUG=1
  857.               Comms_Debug{"Received Sync Reply no: " + Str$(sync_reply_number) + " from Player: " + Str$(player), #MEDIUM}
  858.             CEND
  859.  
  860.             If \average_ping=0
  861.               \average_ping=players(player)\lag
  862.             EndIf
  863.             If ping < \average_ping + #SYNC_ALLOWANCE
  864.               If ping > \average_ping - #SYNC_ALLOWANCE
  865.                 \number_of_similar_pings+1
  866.                 \average_ping=(\average_ping + ping) / 2
  867.               EndIf
  868.             EndIf
  869.  
  870.             If sync_reply_number= #NUMBER_TIME_SYNCS
  871.               CNIF #TEST_TIME_SYNC=1
  872.                 If temp_no=2
  873.                   \number_of_similar_pings=1   ; to test number of similar pings
  874.                   temp_no=3
  875.                 EndIf
  876.               CEND
  877.  
  878.               If \number_of_similar_pings > #MIN_NUMBER_OF_SYNCS
  879.  
  880.                 closest_to_average=0
  881.                 closest_ping.l=Abs(\average_ping - \ping_time[0])
  882.                 For i=1 To #NUMBER_TIME_SYNCS
  883.                   If Abs(\average_ping - \ping_time[i]) < closest_ping
  884.                     closest_to_average=i
  885.                     closest_ping=Abs(\average_ping -\ping_time[i])
  886.                   EndIf
  887.                 Next
  888.                 send$=CP_CALCULATED_TIME.s + Mki$(closest_to_average)
  889.                 send$=send$ + Mkl$(\ping_start[closest_to_average] + \ping_time[closest_to_average] /2 )
  890.                 Send_Reliable_Message{&send$,Len(send$),player,#PEER_TO_PEER,#UNORDERED}
  891.                 CNIF #COMMS_DEBUG=1
  892.                   text$="Sent Calculated Time: " + Str$(\ping_start[closest_to_average] + \ping_time[closest_to_average] /2 )
  893.                   Comms_Debug{text$ +  " to Player " + Str$(player),#MEDIUM}
  894.                 CEND
  895.               Else        ; wait for all sync packets to come in and then restart time sync from beginning
  896.                 \current_sync=0
  897.                 \average_ping=0
  898.                 \number_of_similar_pings=0
  899.                 \last_in_order_ping_number=0
  900.                 \waiting_for_restart=False
  901.                 For i=0 To #NUMBER_TIME_SYNCS
  902.                   \sync_received[i]=False
  903.                 Next
  904.  
  905.                 CNIF #COMMS_DEBUG=1
  906.                   Comms_Debug{"Not enough similar Pings- Restarting Sync to Player: " + Str$(player),#MEDIUM}
  907.                 CEND
  908.               EndIf
  909.             EndIf
  910.           Else
  911.             If \last_in_order_ping_number=#NUMBER_TIME_SYNCS  ; restart time sync from the beginning
  912.               \current_sync=0
  913.               \average_ping=0
  914.               \number_of_similar_pings=0
  915.               \last_in_order_ping_number=0
  916.               \waiting_for_restart=False
  917.               For i=0 To #NUMBER_TIME_SYNCS
  918.                 \sync_received[i]=False
  919.               Next
  920.               CNIF #COMMS_DEBUG=1
  921.                 Comms_Debug{"Restarting Sync to Player: " + Str$(player),#MEDIUM}
  922.               CEND
  923.             EndIf
  924.           EndIf
  925.         EndIf
  926.       Else                       ; if Client
  927.         If player=#SERVER_NUMBER
  928.           USEPATH time_syncs(#SERVER_NUMBER)
  929.           If sync_reply_number<= #NUMBER_TIME_SYNCS
  930.             \ping_start[sync_reply_number]=system_time
  931.             send$=CP_TIME_SYNC_ACK.s + Mki$(sync_reply_number) + Mkl$(incoming_packet_number)
  932.             Send_Reliable_Message{&send$,Len(send$),#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED}
  933.             CNIF #COMMS_DEBUG=1
  934.               Comms_Debug{"Received Time Sync from Server, number: "+ Str$(sync_reply_number),#LOW}
  935.             CEND
  936.           EndIf
  937.         EndIf
  938.       EndIf
  939.     EndIf
  940.   Else       ; Server is resyncing itself from a Client's time
  941.     current_synched_player=0
  942.  EndIf
  943. End Statement
  944.  
  945. Statement Send_Player_Info{player_info_from,player_info_to}
  946.   SHARED players(),host(),player_info_buffer.l
  947.   SHARED CP_REP_PLAYER_INFO.s
  948.  
  949.   If players(player_info_to)\status > #OFFLINE AND players(player_info_from)\status  > #OFFLINE
  950.     If player_info_from <> player_info_to
  951.       send$=CP_REP_PLAYER_INFO.s + Mki$(player_info_from) + Mkl$(host(player_info_from)\sin_addr\s_addr)
  952.       send$=send$ + Mki$(host(player_info_from)\sin_port)
  953.  
  954.       player_info_start.l=player_info_buffer.l + (player_info_from-1) * #PLAYER_INFO_BUFFER_SIZE
  955.       player_info_length.l=NPeekL(player_info_start)
  956.       slength=Len(send$)
  957.       text$=LSet$(send$,player_info_length + slength)
  958.  
  959.       a=CopyMem_(player_info_start+4, &text$ +9 ,player_info_length)
  960.       Send_Reliable_Message{&text$,Len(text$),player_info_to,#PEER_TO_PEER,#UNORDERED}    ; tell new player of others online
  961.     EndIf
  962.   EndIf                                                                ; and give them their info.
  963. End Statement
  964.  
  965. Function.l Get_Game_Data{}
  966.   SHARED incoming_game_data.l,incoming_game_data_status
  967.   If incoming_game_data_status=False
  968.     Function Return False
  969.   Else
  970.     incoming_game_data_status=False
  971.     Function Return incoming_game_data
  972.   EndIf
  973. End Function
  974.  
  975. .Requested_Connection      ; a player is trying to log in to us
  976. Statement Requested_Connection{incoming_buffer.l}
  977.   SHARED sock,players(),host(),hostlen(),GAME_NAME.s
  978.   SHARED temphost,temphostlen,online,my_number,max_number_players
  979.   SHARED CP_REP_ACCEPT.s,CP_REP_REJECT.s
  980.  
  981.   buffer_length=NPeekW(incoming_buffer-2)
  982.   If online=#SERVER  ; If offline or Server
  983.     dummy=4
  984.     exit=False
  985.     Repeat            ; build game name string from incoming request
  986.       dummy+1
  987.       b$=Chr$(NPeekB(incoming_buffer+dummy))
  988.       If b$<>Chr$(0)
  989.         c$=c$+b$
  990.       Else
  991.         exit=True
  992.       EndIf
  993.     Until exit=True OR dummy=buffer_length
  994.  
  995.     If b$=Chr$(0)
  996.       If c$=GAME_NAME.s            ; if request is for correct game
  997.         protocol=NPeekB(incoming_buffer+dummy+1)
  998.         If protocol=#NET_PROTOCOL_VERSION  ; check wether using the same protocol
  999.           a$="Connection request from "
  1000.           player=1
  1001.           exit=0
  1002.           Repeat      ;check if a spare player slot is availiable
  1003.             player+1
  1004.             If players(player)\status=#OFFLINE
  1005.               exit=1
  1006.             Else
  1007.               If player=max_number_players
  1008.                 exit=1
  1009.                 player=-1
  1010.               EndIf
  1011.             EndIf
  1012.           Until exit=1
  1013.  
  1014.           If player>0     ; connection accepted
  1015.             If Get_Host_By_Address{&temphost\sin_addr\s_addr,temphost\sin_port,player}=False
  1016.               Security_Warning{Str$(temphost\sin_addr\s_addr) + "- Host not found!",#SYSTEM_MESSAGE}
  1017.               Statement Return
  1018.             EndIf
  1019.  
  1020.             players(player)\status=#ATTEMPTING_TO_CONNECT
  1021.  
  1022.             temp$=Get_Ascii_Address{host(player)\sin_addr\s_addr}
  1023.  
  1024.             a$=a$+temp$ + "  Port: " + Str$(host(player)\sin_port)
  1025.             players(player)\ascii_host_string=temp$   ; store it
  1026.  
  1027.             send$=CP_REP_ACCEPT.s
  1028.             send$=send$ + Mki$(player) + Mki$(map)  ; send connection accepted back to client
  1029.             players(player)\disconnect_requested=False
  1030.             Send_Reliable_Message{&send$,Len(send$),player,#PEER_TO_PEER,#UNORDERED}
  1031.  
  1032.             Security_Warning{a$,#SYSTEM_MESSAGE}
  1033.             Statement Return
  1034.           Else
  1035.             a$="Connection Request rejected- no spare player slot!"
  1036.           EndIf
  1037.         Else
  1038.           a$="Connection Request rejected- Incorrect Protocol: "+Str$(protocol)
  1039.         EndIf
  1040.       Else
  1041.         a$="Connection Request rejected- wrong game name: "+b$
  1042.       EndIf
  1043.     Else
  1044.       a$="Connection Request rejected- Unknown error!"
  1045.     EndIf
  1046.   Else
  1047.     a$="Connection Request rejected- host already logged on as Client"
  1048.   EndIf
  1049.  
  1050.   send$=Mkl$(0) + CP_REP_REJECT.s + a$    ; send connection rejected back with reason
  1051.   WriteUDP{&send$,Len(send$),0}  ; reply to sender
  1052.   Security_Warning{a$,#MEDIUM}
  1053.  
  1054. End Statement
  1055.  
  1056. .Decode_Packet      ; Decode incoming packet and act accordingly
  1057. Function Decode_Packet{}
  1058.   SHARED players(),host(),temphost,online,unreliable_packet_in()
  1059.   SHARED my_number,player_honesty(),max_number_players
  1060.   SHARED login_stage(),time_sync,time_syncs(),system_time,mtu
  1061.   SHARED player_info_buffer.l,player_info_buffer_size.l,player_info()
  1062.   SHARED new_player,incoming_game_data.l,incoming_game_data_status
  1063.   SHARED disconnect_timeout
  1064.   SHARED CP_REQ_PLAYER_DISCONNECT.s,CP_END_GAME_REC.s,REL_PACKET_ACK.s,CP_REP_ACCEPT.s
  1065.   SHARED CP_GAME_END.s,CP_REP_PLAYER_DISCONNECTED.s,PING_REQUEST.s
  1066.   SHARED PING_RESPONSE.s,CP_START_GAME.s,CP_START_GAME_ACK.s
  1067.   SHARED CP_REP_ACCEPT_ACK.s,CP_REP_PLAYER_INFO.s
  1068.   SHARED CP_CALCULATED_TIME_ACK.s
  1069.  
  1070.   return_code=False
  1071.   incoming_buffer.l=ReadUDP{}   ; get data from socket
  1072.  
  1073.   If incoming_buffer<>False      ; if there was some data waiting
  1074.     incoming_packet_number.l=NPeekL(incoming_buffer)
  1075.     packet_type=NPeekB(incoming_buffer+4) AND $FF ; check buffer for packet type and convert to a word
  1076.     player=Get_Packet_Source{}  ; check to see if packet is from reliable online source
  1077.     next_select=False
  1078.     unknown_packet=False   ; check to see if valid packet is received
  1079.     return_message=0
  1080.     player_known=True
  1081.     connecting_player=False
  1082.  
  1083.     If player>0
  1084.       Select packet_type
  1085.         Case #CP_REQ_CONNECT  ; request to login to Server
  1086.           a$="Connection Request rejected- host already logged on to Server."
  1087.           Security_Warning{Str$(player)+ ": " + a$, #HIGH}
  1088.           send$=Mkl$(0) + CP_REP_REJECT.s + a$    ; send connection rejected back with reason
  1089.           return_message=#DISCONNECTED
  1090.           player_known=False
  1091.  
  1092.         Case #CP_REP_ACCEPT       ; We Received confirmation of logon from Server
  1093.           If player=#SERVER_NUMBER  AND online=#ATTEMPTING_TO_CONNECT
  1094.             my_number=NPeekW(incoming_buffer+5)  ; my player number
  1095.             map.w=NPeekW(incoming_buffer+7)
  1096.             players(#SERVER_NUMBER)\status=#ONLINE  ; Server is now online
  1097.             Security_Warning{"Connection Accepted",#SYSTEM_MESSAGE}
  1098.  
  1099.             send$=Get_My_Player_Info{my_number}   ; get player info from array
  1100.             send$=CP_REP_ACCEPT_ACK.s + Mkl$(incoming_packet_number) + send$
  1101.  
  1102.             If send$<>""                                  ; and put all info into the player info memory block
  1103.               Send_Reliable_Message{&send$,Len(send$),player,#PEER_TO_PEER,#UNORDERED}
  1104.               return_code=#CONNECTED
  1105.               time_sync=#CLIENT
  1106.             Else
  1107.               online=#OFFLINE
  1108.             EndIf
  1109.           Else
  1110.             Security_Warning{"Illegal Reply Accept attempt by player: " + Str$(player),#MEDIUM}
  1111.           EndIf
  1112.  
  1113.         Case #CP_REP_ACCEPT_ACK      ; Login routine at Server
  1114.           If login_stage(player)=0 AND players(player)\status=#ATTEMPTING_TO_CONNECT AND online=#SERVER
  1115.             If Acknowledge_Packet{NPeekL(incoming_buffer+5),player}=True
  1116.  
  1117.               For i=1 To max_number_players
  1118.                 Send_Player_Info{i,player}   ; send to the logging in Player, the other players's info
  1119.               Next
  1120.  
  1121.               time_sync=#SERVER
  1122.               time_syncs(player)\player_synching=True
  1123.               login_stage(player)=1
  1124.               next_select=True
  1125.  
  1126.               CNIF #COMMS_DEBUG=1
  1127.                 Comms_Debug{"Sending New Player other Player's Info, and Starting Time Sync",#MEDIUM}
  1128.                 text$="R " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1129.                 Comms_Debug{text$ + " Packet no. " + Str$(incoming_packet_number) + " arrived at destination.",#HIGH}
  1130.               CEND
  1131.               return_message=#ACKNOWLEDGE_PACKET
  1132.  
  1133.               new_player=player            ; #CP_REP_PLAYER_INFO
  1134.               If new_player <= max_number_players   ; new_player is a global varibale for Main:
  1135.                 host.l=host(player)\sin_addr\s_addr
  1136.                 If New_Player_Info{new_player,host.l,host(player)\sin_port,incoming_buffer+9,NPeekW(incoming_buffer-2)-9}
  1137.                   return_code=#NEW_PLAYER
  1138.                 EndIf
  1139.               Else
  1140.                  Security_Warning{"Illegal Player Number from player: " + Str$(player),#HIGH}
  1141.               EndIf
  1142.  
  1143.             EndIf
  1144.           EndIf
  1145.  
  1146.         Case #CP_REP_REJECT       ; Our logon request was rejected by host
  1147.           If online=#ATTEMPTING_TO_CONNECT AND player=#SERVER_NUMBER
  1148.             size=NPeekW(incoming_buffer-2)
  1149.             temp$=LSet$("",size)
  1150.             a=CopyMem_(incoming_buffer,&temp$,size)
  1151.             Security_Warning{temp$,#SYSTEM_MESSAGE}
  1152.             online=#OFFLINE
  1153.             return_code=#CONNECTION_REJECTED
  1154.           Else
  1155.             Security_Warning{"Illegal Reply Reject attempt by player: " + Str$(player),#MEDIUM}
  1156.           EndIf
  1157.  
  1158.         Case #CP_START_GAME   ; login completed- we can now start game :)
  1159.           If player=#SERVER_NUMBER AND online=#ATTEMPTING_TO_CONNECT
  1160.             online=#CLIENT
  1161.             time_sync=#OFFLINE
  1162.             ;send$=CP_START_GAME_ACK.s
  1163.             return_message=#ACKNOWLEDGE_PACKET
  1164.             CNIF #COMMS_DEBUG=1
  1165.               Comms_Debug{"Received Start Game Message from Server",#MEDIUM}
  1166.             CEND
  1167.             return_code=#START_GAME
  1168.           EndIf
  1169.  
  1170.         Case #CP_REP_PLAYER_INFO  ; Information about new player that has just logged on
  1171.           If online=#ATTEMPTING_TO_CONNECT OR online=#CLIENT  ; if we are a client
  1172.             If player=#SERVER_NUMBER
  1173.               new_player=NPeekW(incoming_buffer+5)
  1174.               If new_player <= max_number_players
  1175.                 If New_Player_Info{new_player,0,0,incoming_buffer+7,NPeekW(incoming_buffer-2)-7}
  1176.                   return_code=#NEW_PLAYER
  1177.                   return_message=#ACKNOWLEDGE_PACKET
  1178.                 EndIf
  1179.               Else
  1180.                  Security_Warning{"Illegal Player Number from player: " + Str$(player),#HIGH}
  1181.               EndIf
  1182.             Else
  1183.               Security_Warning{"Illegal Player Info Reply from player: " + Str$(player),#HIGH}
  1184.             EndIf
  1185.           Else
  1186.             Security_Warning{"Illegal Player Info Reply from player: " + Str$(player),#HIGH}
  1187.           EndIf
  1188.  
  1189.         Case #CP_REQ_PLAYER_DISCONNECT  ; Request from client to disconnect
  1190.             ; or inform Server of disconnected player
  1191.           If online=#SERVER  ; only if Server, and from legal player
  1192.              disconnecting_player=NPeekW(incoming_buffer+5)
  1193.             If player=disconnecting_player  ; if player is leaving game
  1194.               Disconnect_Player{player}
  1195.             Else    ; Ping suspect player to see if they're still online
  1196.               If players(disconnecting_player)\status=#ONLINE
  1197.                 player_honesty(player,disconnecting_player)=True  ; record which player claims another is offline.
  1198.                 Send_Reliable_Message{&PING_REQUEST.s,1,disconnecting_player,#PEER_TO_PEER,#UNORDERED} ; so we can disco
  1199.                 CNIF #COMMS_DEBUG=1
  1200.                   text$="R " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1201.                   text$=text$ + "Player " + Str$(player) + " claims player " + Str$(disconnecting_player)
  1202.                   Comms_Debug{text$ + " has disconnected",#HIGH}
  1203.                 CEND
  1204.               Else
  1205.                 CNIF #COMMS_DEBUG=1
  1206.                   text$="Warning: Player " + Str$(player) + " says UNCONNECTED PLAYER " + Str$(disconnecting_player)
  1207.                   text$=text$ + " is unreachable."
  1208.                   Comms_Debug{text$,#HIGH}
  1209.                 CEND
  1210.               EndIf
  1211.               return_message=#ACKNOWLEDGE_PACKET
  1212.             EndIf
  1213.           Else
  1214.             Security_Warning{"Illegal Player Disconnect Request Packet from player: " + Str$(player), #MEDIUM}
  1215.           EndIf
  1216.  
  1217.         Case #CP_REP_PLAYER_DISCONNECTED    ; Server has told us a player has disconnected from the game
  1218.                                             ; - this can be us as well
  1219.           If player=#SERVER_NUMBER AND online>#OFFLINE   ; only if we're a client and message is fro
  1220.             disconnected_player=NPeekW(incoming_buffer+5)
  1221.             Clear_Player_Arrays{disconnected_player}     ; player is now offline
  1222.             If disconnected_player=my_number ; my disconnection request has been confirmed by Server
  1223.               online=#OFFLINE          ; go offline
  1224.               For a= 1 To max_number_players
  1225.                 If players(a)\status=#ONLINE
  1226.                   Clear_Player_Arrays{a}
  1227.                 EndIf
  1228.               Next
  1229.               disconnect_timeout=0
  1230.               Security_Warning{"We are disconnected from the game.",#SYSTEM_MESSAGE}
  1231.               return_code=#DISCONNECTED
  1232.             Else
  1233.               temp$="Player " + Str$(disconnected_player)
  1234.               Security_Warning{temp$ + " is disconnected from the game.",#SYSTEM_MESSAGE}
  1235.             EndIf
  1236.             return_message=#ACKNOWLEDGE_PACKET
  1237.           Else
  1238.             Security_Warning{"Illegal Player Disconnected Reply Packet from player: " + Str$(player),#MEDIUM}
  1239.           EndIf
  1240.  
  1241.         Case #CP_END_GAME   ; Server has ended Game
  1242.           If player=#SERVER_NUMBER AND online>#OFFLINE  ; if message is from Server
  1243.             send$=CP_END_GAME_REC.s
  1244.             Send_Reliable_Message{&send$,Len(send$),#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED}
  1245.             online=#OFFLINE
  1246.             return_message=#ACKNOWLEDGE_PACKET
  1247.             Security_Warning{"Server has shut down game.",#SYSTEM_MESSAGE}
  1248.             For a= 1 To max_number_players
  1249.               If players(a)\status=#ONLINE
  1250.                 Clear_Player_Arrays{a}
  1251.               EndIf
  1252.             Next
  1253.             disconnect_timeout=0
  1254.             return_code=#DISCONNECTED
  1255.           Else
  1256.             Security_Warning{"Illegal End Game attempt by player: " + Str$(player),#MEDIUM}
  1257.           EndIf
  1258.  
  1259.         Case #CP_END_GAME_REC  ; player has confirmed they received the Game End packet
  1260.           If online=#SERVER
  1261.             Clear_Player_Arrays{player}      ; player is now offline
  1262.             dummy=0
  1263.             For i=2 To max_number_players
  1264.               If players(i)\status=#ONLINE   ; check to see if all players are offline
  1265.                 dummy=1
  1266.               EndIf
  1267.             Next
  1268.             If dummy=0   ; if all players are offline
  1269.               online=#OFFLINE
  1270.               CNIF #COMMS_DEBUG=1
  1271.                 text$="R " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1272.                 Comms_Debug{text$ + "Player " + Str$(player) + " has confirmed game closure.",#HIGH}
  1273.               CEND
  1274.               Security_Warning{"All players have confirmed game has shut down.",#SYSTEM_MESSAGE}
  1275.               return_code=#DISCONNECTED
  1276.  
  1277.             CNIF #COMMS_DEBUG=1
  1278.             Else
  1279.               text$="R " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1280.               Comms_Debug{text$ + "Player " + Str$(player) + " has confirmed game closure.",#HIGH}
  1281.             CEND
  1282.  
  1283.             EndIf
  1284.             return_message=#ACKNOWLEDGE_PACKET
  1285.           Else
  1286.             Security_Warning{"Illegal END_GAME_REC packet received from: " + Str$(player),#MEDIUM}
  1287.           EndIf
  1288.  
  1289.         Case #CP_TIME_SYNC
  1290.           If online > #OFFLINE
  1291.             Time_Sync{#RECEIVE,player,NPeekW(incoming_buffer+5),incoming_packet_number}
  1292.             CNIF #COMMS_DEBUG=1
  1293.               ;Comms_Debug{"Received Time Sync from Player: " + Str$(player),#MEDIUM}
  1294.             CEND
  1295.           Else
  1296.  
  1297.           EndIf
  1298.  
  1299.         Case #CP_TIME_SYNC_ACK  ; time sync reply
  1300.           If online > #OFFLINE
  1301.             If Acknowledge_Packet{NPeekL(incoming_buffer+7),player}=True
  1302.  
  1303.               Time_Sync{#RECEIVE,player,NPeekW(incoming_buffer+5),0}
  1304.               CNIF #COMMS_DEBUG=1
  1305.                 text$="R " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1306.                 Comms_Debug{text$ + " Packet no. " + Str$(incoming_packet_number) + " arrived at destination.",#HIGH}
  1307.                 Comms_Debug{"Received Time Sync Ack from Player: " + Str$(player),#MEDIUM}
  1308.                 Comms_Debug{"System time is: " + Str$(system_time),#MEDIUM}
  1309.               CEND
  1310.  
  1311.             EndIf
  1312.             return_message=#ACKNOWLEDGE_PACKET
  1313.           Else
  1314.  
  1315.           EndIf
  1316.  
  1317.         Case #CP_CALCULATED_TIME  ; Server finalises time
  1318.           If player=#SERVER_NUMBER  AND online > #OFFLINE
  1319.             time_difference.l=system_time - time_syncs(#SERVER_NUMBER)\ping_start[NPeekW(incoming_buffer+5)]
  1320.             CNIF #COMMS_DEBUG=1
  1321.               Comms_Debug{"Sys time "  + Str$(system_time),#MEDIUM}
  1322.             CEND
  1323.             system_time=NPeekL(incoming_buffer+7) + time_difference
  1324.             send$=CP_CALCULATED_TIME_ACK.s + Mkl$(incoming_packet_number)
  1325.             Send_Reliable_Message{&send$,5,#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED}
  1326.             time_sync=False
  1327.             CNIF #COMMS_DEBUG=1
  1328.               text$="Received Calculated Time from Player " + Str$(player) +" - system time is now: "
  1329.               Comms_Debug{text$ + Str$(system_time),#MEDIUM}
  1330.               Comms_Debug{"old time: "  + Str$(NPeekL(incoming_buffer+7)),#LOW}
  1331.               Comms_Debug{"best average: "  + Str$(NPeekW(incoming_buffer+5)),#LOW}
  1332.               text$="Ping_start: "
  1333.               Comms_Debug{text$ + Str$(time_syncs(#SERVER_NUMBER)\ping_start[NPeekW(incoming_buffer+5)]),#LOW}
  1334.              CEND
  1335.           Else
  1336.             If online > #OFFLINE
  1337.               Security_Warning{"Calculated time message received while Offline.",#HIGH}
  1338.             Else
  1339.               Security_Warning{"Illegal Calculated time message from Player: " + Str$(player),#HIGH}
  1340.             EndIf
  1341.           EndIf
  1342.  
  1343.         Case #CP_CALCULATED_TIME_ACK
  1344.           If online=#SERVER      ; login routine at server
  1345.             If login_stage(player)=1 AND players(player)\status=#ATTEMPTING_TO_CONNECT
  1346.               ; player's time has been synched so we now can now start game
  1347.  
  1348.               For i=2 To max_number_players
  1349.                 If players(i)\status > #OFFLINE
  1350.                   Send_Player_Info{player,i}  ; tell others players that new player is online
  1351.                                               ; and give them new players info.
  1352.                 EndIf
  1353.               Next
  1354.  
  1355.               Send_Reliable_Message{&CP_START_GAME.s,1,player,#PEER_TO_PEER,#UNORDERED}  ; tell new player to start game
  1356.               players(player)\status=#ONLINE
  1357.  
  1358.               CNIF #COMMS_DEBUG=1
  1359.                  Comms_Debug{"New Player " + Str$(player) + "  has Synched Time and Is Now Online",#HIGH}
  1360.               CEND
  1361.             EndIf
  1362.           EndIf
  1363.  
  1364.           If Acknowledge_Packet{NPeekL(incoming_buffer+5),player}=True
  1365.             USEPATH time_syncs(player)
  1366.             \player_synching=False
  1367.             \current_sync=0
  1368.             \average_ping=0
  1369.             \number_of_similar_pings=0
  1370.             \last_in_order_ping_number=0
  1371.             \waiting_for_restart=False
  1372.             For i=1 To #NUMBER_TIME_SYNCS
  1373.               \sync_received[i]=False
  1374.             Next
  1375.             a=False : i=1
  1376.             Repeat
  1377.               i+1
  1378.               If time_syncs(player)\player_synching=True
  1379.                 a=True
  1380.               EndIf
  1381.             Until a=True OR i=max_number_players
  1382.  
  1383.             If a=False
  1384.               time_sync=False
  1385.             EndIf
  1386.  
  1387.             CNIF #COMMS_DEBUG=1
  1388.               text$="R " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1389.               Comms_Debug{text$ + " Packet no. " + Str$(incoming_packet_number) + " arrived at destination.",#HIGH}
  1390.               Comms_Debug{"Received Calculated Time Ack from Player: " + Str$(player),#MEDIUM}
  1391.             CEND
  1392.           EndIf
  1393.           return_message=#ACKNOWLEDGE_PACKET
  1394.  
  1395.         Case #REL_STRING_END     ; basic string message received from a player
  1396.           If online>#ATTEMPTING_TO_CONNECT
  1397.             size=NPeekW(incoming_buffer-2)-6
  1398.             CNIF #COMMS_DEBUG=1
  1399.               text$="R " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1400.  
  1401.  
  1402.               temp$=LSet$("",size)
  1403.               a=CopyMem_(incoming_buffer+5,&temp$,size)
  1404.               Comms_Debug{text$ + temp$,#MEDIUM}
  1405.             CEND
  1406.  
  1407.             incoming_game_data_status=True
  1408.             NPokeW incoming_game_data,size
  1409.             NPokeW incoming_game_data+2,#REL_STRING_END
  1410.             NPokeW incoming_game_data+4,player
  1411.             a=CopyMem_(incoming_buffer+5,incoming_game_data+6,size)  ; copy incoming data to user
  1412.  
  1413.             return_message=#ACKNOWLEDGE_PACKET
  1414.           EndIf
  1415.  
  1416.         Case #UNRELIABLE_PACKET  ; an unreliable packet has been received- no acknowledgement needed
  1417.           If online>#ATTEMPTING_TO_CONNECT
  1418.             If incoming_packet_number > unreliable_packet_in(player)   ; lastest unreliable message
  1419.               size=NPeekW(incoming_buffer-2)-5
  1420.               CNIF #COMMS_DEBUG=1
  1421.                  text$="RU " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1422.                  temp$=LSet$("",size)
  1423.                  a=CopyMem_(incoming_buffer+5,&temp$,size)
  1424.                  Comms_Debug{text$ + temp$,#MEDIUM}
  1425.               CEND
  1426.               unreliable_packet_in(player)=incoming_packet_number    ; make this packet number the highest number received
  1427.               incoming_game_data_status=True
  1428.  
  1429.               NPokeW incoming_game_data,size
  1430.               NPokeW incoming_game_data+2,#UNRELIABLE_PACKET
  1431.               NPokeW incoming_game_data+4,player
  1432.               a=CopyMem_(incoming_buffer+5,incoming_game_data+6,size)  ; copy incoming data to user
  1433.  
  1434.             Else                 ; if this packet is slow and has got out of order
  1435.               CNIF #COMMS_DEBUG=1                                    ; ignore it
  1436.                 text$="RU " + Str$(incoming_packet_number) + "," + Str$(player)  + " Out-of-Order: "
  1437.                 size=NPeekW(incoming_buffer-2)-5
  1438.                 temp$=LSet$("",size)
  1439.                 a=CopyMem_(incoming_buffer+5,&temp$,size)
  1440.                 Comms_Debug{text$ + temp$,#MEDIUM}
  1441.               CEND
  1442.             EndIf                                                                           ; interface buffer
  1443.           EndIf
  1444.  
  1445.         Case #REL_PACKET_ACK     ; a message has been received by a player
  1446.           If online>#OFFLINE
  1447.             If Acknowledge_Packet{incoming_packet_number,player}=True
  1448.               CNIF #COMMS_DEBUG=1
  1449.                 text$="R " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1450.                 Comms_Debug{text$ + " Packet no. " + Str$(incoming_packet_number) + " arrived at destination.",#HIGH}
  1451.               CEND
  1452.             EndIf
  1453.           EndIf
  1454.  
  1455.         Case #PING_REQUEST       ; a Ping request has been received
  1456.           CNIF #COMMS_DEBUG=1
  1457.             text$="R " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1458.             Comms_Debug{text$ + "Player " + Str$(player) + " has sent a Ping request.",#HIGH}
  1459.           CEND
  1460.  
  1461.           If player=#SERVER_NUMBER AND online=#CLIENT
  1462.             return_message=#ACKNOWLEDGE_PACKET
  1463.             Send_Reliable_Message{&PING_RESPONSE.s,1,player,#PEER_TO_PEER,#UNORDERED} ; send Ping Response back
  1464.           Else
  1465.             Security_Warning{"Illegal PING_REQUEST received from player: " + Str$(player), #MEDIUM}
  1466.           EndIf
  1467.  
  1468.         Case #PING_RESPONSE      ; Ping response received
  1469.  
  1470.           If online=#SERVER
  1471.             CNIF #COMMS_DEBUG=1
  1472.               text$="R " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1473.               Comms_Debug{text$ + "Player " + Str$(player) + " has  sent a Ping response.",#HIGH}
  1474.             CEND
  1475.  
  1476.             For a= 1 To max_number_players     ; this is to stop players from disconnecting other players illegally
  1477.               If player_honesty(a,player)=True  ; if player loses connection to other player
  1478.                 Disconnect_Player{a}       ; Disconnect player who has lost connection to another player
  1479.                 CNIF #COMMS_DEBUG=1
  1480.                   text$="R " + Str$(incoming_packet_number) + "," + Str$(player)  + ": "
  1481.                   Comms_Debug{text$ + "Player " + Str$(a) + " has lost connection to player " + Str$(player),#HIGH}
  1482.                 CEND
  1483.               EndIf
  1484.             Next
  1485.           Else
  1486.             Security_Warning{"Illegal PING_RESPONSE received from player: " + Str$(player), #MEDIUM}
  1487.           EndIf
  1488.  
  1489.         Default
  1490.           unknown_packet=True
  1491.       End Select
  1492.     Else            ; if player unknown
  1493.       Requested_Connection{incoming_buffer} ; player is attempting to connect to Server
  1494.       player_known=False
  1495.     EndIf
  1496.  
  1497.     If unknown_packet=True
  1498.       If player=-1 AND player_known=True ; if from unknown source
  1499.         temp$="Unknown Source: " + Get_Ascii_Address{temphost\sin_addr\s_addr} + " Port: " + Str$(temphost\sin_port)
  1500.       Else                         ; from known source
  1501.         temp$="Player: " + Str$(player)
  1502.       EndIf
  1503.       Security_Warning{"Unknown Packet from " + temp$,#MEDIUM}
  1504.       Function Return False
  1505.     Else
  1506.       If player=-1 AND player_known=True  ; if from unknown source
  1507.         temp$=": " + Get_Ascii_Address{temphost\sin_addr\s_addr} + " Port: " + Str$(temphost\sin_port)
  1508.         Security_Warning{"Known Packet from Unknown Source" + temp$,#MEDIUM}
  1509.         Function Return False
  1510.       EndIf
  1511.     EndIf
  1512.  
  1513.     If return_message>0
  1514.       If return_message=#ACKNOWLEDGE_PACKET  ; send packet acknowledgment back
  1515.         send$=Mkl$(incoming_packet_number)  + REL_PACKET_ACK.s  ;
  1516.       EndIf
  1517.       WriteUDP{&send$,Len(send$),player}  ; return a message back if return_message = 1 or 3
  1518.     EndIf
  1519.   EndIf
  1520.  
  1521.   Function Return return_code
  1522. End Function
  1523.  
  1524. .Comms_Housekeeping
  1525. Function Comms_Housekeeping{}
  1526.   SHARED messages(),last_message_number(),players(),online
  1527.   SHARED max_wait,max_number_players,disconnect_timeout
  1528.   SHARED player_housekeeping,system_time,time_sync
  1529.  
  1530.   return_code=Decode_Packet{}    ; find out what was in the packet
  1531.  
  1532.   player_housekeeping+1
  1533.   If player_housekeeping=max_number_players+1
  1534.     player_housekeeping=1
  1535.   EndIf
  1536.   If messages(player_housekeeping,last_message_number(player_housekeeping))\ack=False  ; only check if there's messages that hav
  1537.     If system_time>messages(player_housekeeping,last_message_number(player_housekeeping))\timestamp+max_wait  ; has it been 5 se
  1538.       Resend_Message{player_housekeeping,last_message_number(player_housekeeping)}  ; if run out of resends- disconnect player
  1539.     EndIf
  1540.   EndIf
  1541.  
  1542.   If disconnect_timeout>0   ; If disconnection timeout reaches
  1543.     disconnect_timeout-1    ; zero then disconnect the program
  1544.     If disconnect_timeout=0
  1545.       online=#OFFLINE          ; go offline
  1546.       For a= 1 To max_number_players
  1547.         If players(a)\status=#ONLINE
  1548.           Clear_Player_Arrays{a}
  1549.         EndIf
  1550.       Next
  1551.       my_number=0
  1552.       Security_Warning{"We are disconnected from the game.",#SYSTEM_MESSAGE}
  1553.       return_code=#DISCONNECTED
  1554.     EndIf
  1555.   EndIf
  1556.  
  1557.   If time_sync>False
  1558.     Time_Sync{#SEND,0,0,0}    ; check for any Time Synching that needs doing
  1559.   EndIf
  1560.  
  1561.   Function Return return_code
  1562. End Function
  1563.  
  1564. ;***************************************************************
  1565. ;***********************  End of UDP Stuff  ********************
  1566. ;***************************************************************
  1567.  
  1568. ;***************************************************************
  1569. ;**************************  Game stuff  ***********************
  1570. ;***************************************************************
  1571. ;   Everything below is for UDP_Chat, and is an example of
  1572. ;   putting the UDP_Funcs into your game.
  1573.  
  1574. ;******************* Game Variables and Constants **************
  1575.  
  1576. exit=False
  1577. game_closing=0
  1578. PORT_NAME.s="UDP_Chat"  ; "UDP_Chat"  Rexx portname
  1579. #LOCALPORT=27272        ; 27272 default local port to send an receive from
  1580. #PORT=27272     ; 27272 default destination port to send data to
  1581. #RELIABLE=0
  1582. #UNRELIABLE=1
  1583. print_player.w=1
  1584. message_type=#RELIABLE
  1585.  
  1586. ;************************  Game Dims  **************************
  1587.  
  1588. Dim pingprintx(max_number_players)
  1589.  
  1590. ;*******************     Game Functions     ********************
  1591. ;
  1592. ;  These Functions are specific to your program, the ones below
  1593. ;  can be used as examples for your game.
  1594.  
  1595. .Print_String                ; Print a string in window and scroll if necessary
  1596. Statement Print_String{text$}
  1597.   SHARED ypos
  1598.   If ypos<200
  1599.     ypos+10
  1600.   Else
  1601.     WScroll 10,60,590,220,0,10
  1602.   EndIf
  1603.  
  1604.   WLocate 10,ypos
  1605.   Print text$               ; print string received
  1606. End Statement
  1607.  
  1608. .Window_Events
  1609. Function Window_Events{}
  1610.   SHARED pingwidth,hostnamey,online,players(),my_number,packet_number()
  1611.   SHARED game_closing.w,max_number_players,pingprintx(),hostname
  1612.   SHARED port_used,message_type,unreliable_packet_out(),system_time
  1613.   SHARED REL_STRING_END.s
  1614.  
  1615.   exit=False
  1616.   ev.l=Event    ; get window events
  1617.   Select ev
  1618.     Case $40   ; if a gadget has been hit
  1619.       Select GadgetHit
  1620.         Case51           ; Try to connect to a Server
  1621.           If Connect_to_Server{GTGetString(0,51), GTGetInteger(0,52)}=True
  1622.             WLocate 502,4
  1623.             Print "Bound to: ",port_used
  1624.           Else
  1625.             Print_String{"Unable to Initialise UDP"}
  1626.           EndIf
  1627.  
  1628.         Case52           ; Port to connect at above Server
  1629.           If Get_Host_By_Name{GTGetString(0,51), GTGetInteger(0,52),1} : EndIf
  1630.  
  1631.         Case53    ; Server button- lets our program become the Server
  1632.           If Initialise_Server{#LOCALPORT}
  1633.             Print_String {"Bound to " + hostname + " "+ Str$(port_used)}
  1634.             WLocate 502,4
  1635.             Print "Bound to: ",port_used
  1636.             WLocate pingprintx(#SERVER_NUMBER),32
  1637.             Print "Serv"         ; show that we're Server
  1638.             Print_String{"We are set up as Server."}
  1639.           Else
  1640.             Print_String{"Couldn't Initialise Server!"}
  1641.           EndIf
  1642.  
  1643.         Case54           ; get name of localhost
  1644.           a$=Localhost_Name {}   ;
  1645.           WLocate 5+pingwidth+15,hostnamey+3
  1646.           Print a$
  1647.  
  1648.         Case 55    ; button 1
  1649.           Print_String{"Delay program for 1 second"}
  1650.           VWait 50     ; put in artificial delay of 1 second For testing purposes
  1651.           Print_String{"Delay Ended"}
  1652.  
  1653.         Case 56    ; button 2
  1654.           Print_String{"Delay program for 80 seconds"}
  1655.           VWait 4000   ;  put in artificial delay of 80 seconds for testing purposes- causes you to lose connection
  1656.           Print_String{"Delay Ended"}
  1657.  
  1658.         Case 57    ; button 3        ; print system time
  1659.           Print_String{"Current System Time: " + Str$(system_time)}
  1660.  
  1661.         Case 61    ; button 7- toggle between sending Reliable and unreliable messages
  1662.           If message_type=#RELIABLE
  1663.             message_type=#UNRELIABLE
  1664.             Print_String{"Send Unreliable messages."}
  1665.           Else
  1666.             message_type=#RELIABLE
  1667.             Print_String{"Send Reliable messages."}
  1668.           EndIf
  1669.  
  1670.         Case62   ; button 8- Pause program
  1671.           Print_String{"PAUSED"}
  1672.           Repeat
  1673.              ev.l=WaitEvent
  1674.              If ev=$40
  1675.                 Select GadgetHit
  1676.                  Case 62
  1677.                   unpause= 1
  1678.                   Print_String{"UNPAUSED"}
  1679.                 End Select
  1680.              EndIf
  1681.            Until unpause=1
  1682.  
  1683.         Case63    ; Disconnect button- disconnects us from the game
  1684.           If online=#OFFLINE
  1685.             Print_String{"We're already offline."}
  1686.           Else
  1687.             If Disconnect_From_Game{}
  1688.               Print_String{"Game has ended."}
  1689.               For i=1 To 8
  1690.                 WLocate pingprintx(i),32
  1691.                 Print "    "     ; Clear the lag times
  1692.               Next
  1693.             EndIf
  1694.           EndIf
  1695.         Case64         ; Send string message to connected players
  1696.           If online>#ATTEMPTING_TO_CONNECT
  1697.               temp$=GTGetString(0,64)
  1698.               For i=1 To 8
  1699.                 If players(i)\status=#ONLINE  AND i<>my_number   ; send to player if they're online and it's not my number :)
  1700.                   If message_type=#RELIABLE
  1701.                     Print_String{"S " + Str$(packet_number(i)) + "," + Str$(i)  + ": "+ temp$}
  1702.                     send$=REL_STRING_END.s + temp$ + Chr$(0)
  1703.                     Send_Reliable_Message{&send$,Len(send$),i,#PEER_TO_PEER,#UNORDERED}   ; Send string to players reliably
  1704.                   Else
  1705.                     Print_String{"SU " + Str$(unreliable_packet_out(i)+1) + "," + Str$(i)  + ": "+ temp$}
  1706.                     Send_Unreliable_Message{&temp$,Len(temp$),i,#PEER_TO_PEER}   ; Send string to connected players unreliably
  1707.                   EndIf
  1708.                 EndIf
  1709.               Next
  1710.           EndIf
  1711.       End Select
  1712.     Case $200    ; if close button pressed
  1713.       If Disconnect_From_Game{}
  1714.         exit=True
  1715.         Print_String{"Program Closing."}
  1716.       Else
  1717.         game_closing=#GAME_CLOSING_TIMEOUT
  1718.       EndIf
  1719.   End Select
  1720.  
  1721.   Function Return exit
  1722. End Function
  1723.  
  1724. ;     ARexx code
  1725. ;  It seems replyrexxmsg doesn't actually work for sending result strings
  1726. ;  back, use WRITERESULT, then replymsg for when you want to send
  1727. ;  something back to rexx with result
  1728.  
  1729. Statement Result_Reply{*msg.RexxMsg,resulterror.l,resultstring$}
  1730.   *msg\rm_Result1=result1
  1731.   If ((*msg\rm_Action & #RXFF_RESULT)<>0)&(result1=0)
  1732.     *msg\rm_Result2=CreateArgstring_(&resultstring$,Len(resultstring$))
  1733.   Else
  1734.     *msg\rm_Result2=0
  1735.   EndIf
  1736.   ReplyMsg_ *msg
  1737. End Statement
  1738.  
  1739. .Get_Rexx_Message
  1740. Function Get_Rexx_Message{}
  1741.   SHARED rexxport.l,online
  1742.   rmsg.l=RexxEvent(rexxport)
  1743.   If IsRexxMsg(rmsg)=1
  1744.     rexxline$=GetRexxCommand(rmsg,1)
  1745.     Print_String {rexxline$}
  1746.     linepos=Instr(rexxline$," ")
  1747.     If linepos=0
  1748.       command$=rexxline$
  1749.     Else
  1750.       command$=Left$(rexxline$,linepos-1)
  1751.     EndIf
  1752.     Select command$
  1753.       Case "QUIT"
  1754.           ReplyRexxMsg rmsg,0,0,""
  1755.           Function Return True
  1756.  
  1757.        Case "ISONLINE"
  1758.          Select online
  1759.             Case #OFFLINE
  1760.               Result_Reply{rmsg,0,"Offline"}
  1761.             Case #ATTEMPTING_TO_CONNECT
  1762.               Result_Reply{rmsg,0,"Attempting to Connect"}
  1763.             Case #SERVER
  1764.               Result_Reply{rmsg,0,"Server"}
  1765.             Case #CLIENT
  1766.               Result_Reply{rmsg,0,"Client"}
  1767.           End Select
  1768.  
  1769.       Case "CONNECTTOSERVER"
  1770.           hostname$=Right$(rexxline$,Len(rexxline$)-linepos)
  1771.           Print_String {hostname$}
  1772.           If Connect_to_Server{hostname$,#PORT} : EndIf
  1773.           ScreenToFront_ Peek.l(Addr Screen(0))
  1774.           WindowToFront_ Peek.l(Addr Window(0))
  1775.           ReplyRexxMsg rmsg,0,0,""
  1776.       Default
  1777.         ReplyRexxMsg rmsg,0,0,""
  1778.     End Select
  1779.   EndIf
  1780.   Function Return False
  1781. End Function
  1782.  
  1783. .General_Housekeeping
  1784. Function General_Housekeeping{}
  1785.   SHARED game_closing,online,print_player,pingprintx()
  1786.   SHARED players(),my_number,print_count,max_number_players
  1787.  
  1788.   exit=False
  1789.   If Get_Rexx_Message{}=True  ; check for any arexx messages
  1790.     exit=True                  ; exit if `Quit' received
  1791.   EndIf
  1792.  
  1793.   print_count+1
  1794.   If print_count=50
  1795.     print_count=1  ; do once per second
  1796.     print_player+1
  1797.     If print_player>max_number_players Then print_player=1
  1798.     If online>#ATTEMPTING_TO_CONNECT AND print_player<>my_number
  1799.  
  1800.       WLocate pingprintx(print_player),32
  1801.       If players(print_player)\status=#ONLINE
  1802.         Format "0000"
  1803.         Print Str$(players(print_player)\lag)   ; print lag onscreen
  1804.         Format""
  1805.       Else
  1806.         Print"    "
  1807.       EndIf
  1808.     EndIf
  1809.   EndIf
  1810.  
  1811.   If game_closing>0   ; if game is shutting down
  1812.     If online=#OFFLINE
  1813.       exit=True  ; if all players are offline then shutdown
  1814.       Print_String{"We are now Offline- Closing program."}
  1815.     Else
  1816.       If game_closing>=2    ; carry on countdown
  1817.         game_closing-1
  1818.       Else                  ; if countdown reaches 10 seconds then disconnect regardless
  1819.         exit=True
  1820.         Print_String{"Emergency Shutdown!- unable to disconnect from Server."}
  1821.       EndIf
  1822.     EndIf
  1823.   EndIf
  1824.  
  1825.   Repeat
  1826.     a$=Read_Security_Warning{}
  1827.     If a$<>""
  1828.       Print_String{a$}
  1829.     EndIf
  1830.   Until a$=""
  1831.  
  1832.   CNIF #COMMS_DEBUG=1
  1833.     Repeat
  1834.       a$=Read_Comms_Debug_Messages{}
  1835.       If a$<>""
  1836.         Print_String{a$}
  1837.       EndIf
  1838.     Until a$=""
  1839.   CEND
  1840.  
  1841.   Function Return exit
  1842. End Function
  1843.  
  1844. .Exit
  1845. Statement Exit{text$}
  1846.   SHARED rexxport.l,rexxmsg.l
  1847.  
  1848.   Print_String{text$}    ; print error (if any)
  1849.  
  1850.   ClrInt 5               ; shut down Vblank timer
  1851.  
  1852.   If rexxport>0              ; if we've successfully opened an Arexx port then close it
  1853.     DeleteRexxMsg rexxmsg.l
  1854.     DeleteMsgPort rexxport.l
  1855.     Print_String{"Rexxport closed"}
  1856.   EndIf
  1857.  
  1858.   Close_UDP{}     ; close all UDP stuff down
  1859.  
  1860.   Print_String{"Program exiting"}
  1861.  
  1862.   Delay_(50)
  1863.   End          ; close program
  1864.  
  1865. End Statement
  1866.  
  1867. ;*********************  End of Functions  ***********************
  1868.  
  1869. Gosub Init_Gui
  1870.  
  1871. ;************************  Main  Loop  **************************
  1872.  
  1873. .Main
  1874.  
  1875. Repeat
  1876.  
  1877.     WaitTOF_   ; pause a bit to allow prog to multitask nicely, and sync up display
  1878.     ;NPrint system_time
  1879.     exit=Window_Events{}    ; check for input from user
  1880.  
  1881.     If online>#OFFLINE
  1882.       a=Comms_Housekeeping{}  ; Check for incoming data and do comms housekeeping work.
  1883.       Select a
  1884.         Case #CONNECTED       ; Server has told us we're online
  1885.           WLocate pingprintx(my_number)+5,32
  1886.           Print "Me"         ; print our player number - as a Client.
  1887.         Case #DISCONNECTED    ; We're now offline
  1888.           For i=1 To 8
  1889.             WLocate pingprintx(i),32
  1890.             Print "    "     ; Clear the lag times
  1891.           Next
  1892.           If game_closing>0 Then exit=1
  1893.         Case #CONNECTION_REJECTED ; Our connection attempt was rejected
  1894.  
  1895.  
  1896.         Case #START_GAME
  1897.           Print_String{"We have Started Game :)"}
  1898.  
  1899.         Case #NEW_PLAYER
  1900.           Print_String{"New Player no: " + Str$(new_player)}
  1901.           player_info_start.l=player_info_buffer + (new_player-1) * #PLAYER_INFO_BUFFER_SIZE
  1902.           Print_String{"Player Info size: " + Str$(NPeekL(player_info_start))}
  1903.           player_info_start + 4
  1904.           Print_String{"Player's Colour: " + Str$(NPeekW(player_info_start))}  ; get player colour
  1905.           player_info_start + 2
  1906.           Print_String{"Player's Score: " + Str$(NPeekL(player_info_start))}   ; get player score
  1907.           player_info_start + 4
  1908.  
  1909.           player_info_length.w=NPeekW(player_info_start)                 ; get player name
  1910.           text$=LSet$("",player_info_length)
  1911.           a=CopyMem_(player_info_start + 2, &text$, player_info_length)
  1912.           Print_String{"Player's Name: " + text$}
  1913.           player_info_start + player_info_length + 2
  1914.  
  1915.           player_info_length.w=NPeekW(player_info_start)                ; get player nick
  1916.           text$=LSet$("",player_info_length)
  1917.           a=CopyMem_(player_info_start + 2, &text$, player_info_length)
  1918.           Print_String{"Player's Nick: " + text$}
  1919.           player_info_start + player_info_length + 2
  1920.  
  1921.       End Select
  1922.     EndIf
  1923.  
  1924.     ;*****************   Get Incoming Game Data ****************
  1925.     game_data.l=Get_Game_Data{} ; get incoming game data
  1926.     If game_data>0
  1927.       size=NPeekW(game_data)                 ; get size of data
  1928.       If NPeekW(game_data+2)=#REL_STRING_END
  1929.         text$="R " + Str$(NPeekW(game_data+4)) + ": "    ; Reliable packet received
  1930.       Else
  1931.         text$="RU " + Str$(NPeekW(game_data+4)) + ": "   ; UnReliable Packet received
  1932.       EndIf
  1933.  
  1934.       temp$=LSet$("",size)            ; create temporary string to print it out, the size of the data
  1935.       a=CopyMem_(game_data + 6,&temp$,size)   ; copy data to string
  1936.       text$=text$ + temp$
  1937.       Print_String{text$}                     ; print it out
  1938.     EndIf
  1939.     ;***********************************************************
  1940.  
  1941.     If General_Housekeeping{}=True  ; Check for rexx messages
  1942.       exit=True                ; and do general housekeeping work.
  1943.     EndIf
  1944.  
  1945. Until exit=True    ; shut down if close gadget hit
  1946.  
  1947. Exit{""}   ; close UDP socket and Rexxport, and free read memory buffer
  1948.            ; END!
  1949.  
  1950. ;****************************************************************************
  1951.  
  1952.  
  1953. .Init_Gui            ; setup window and gadgets- note it's a bit hacked from Alvaro Thompson's original code
  1954.   ypos=40
  1955.   WBenchToFront_   ; and isn't proportional and completely font sensitive any more :-/
  1956.   WbToScreen0
  1957.   DefaultIDCMP $20|$40|$200
  1958.   *scr.Screen=Peek.l(Addr Screen(0))
  1959.   *myfont.TextAttr=*scr\Font
  1960.   fontheight=*myfont\ta_YSize
  1961.   ad1.l=*myfont\ta_Name
  1962.   fontname$=Peek$(ad1)
  1963.  
  1964.   LoadFont 1,fontname$,fontheight,0
  1965.  
  1966.   portwidth=TextLength_(*scr\RastPort,"Port:",5)+10
  1967.   numberswidth=TextLength_(*scr\RastPort,"99999",5)+14
  1968.   serverwidth=TextLength_(*scr\RastPort,"Send To:",8)+10
  1969.   connectwidth=TextLength_(*scr\RastPort,"Connect",7)+14
  1970.   disconnectwidth=TextLength_(*scr\RastPort,"Disconnect",10)+14
  1971.   pingwidth=TextLength_(*scr\RastPort,"Localhost:",11)
  1972.   delaywidth=TextLength_(*scr\RastPort,"SERVER",8)+10
  1973.   inputwidth=TextLength_(*scr\RastPort,"Input:",6)+10
  1974.   firstperson=TextLength_(*scr\RastPort,"1:",2)+10
  1975.  
  1976.   #SERVERBTN       =51
  1977.   #PORTBTN         =52
  1978.   #BUTTON          =53
  1979.  
  1980.   x=1
  1981.   y=1
  1982.  
  1983.   x1=x+(serverwidth*3)+portwidth+numberswidth+9+3+connectwidth+5
  1984.  
  1985.   If #NO_CONNECTION=0
  1986.     GTString  0,#SERVERBTN,x+serverwidth,y,serverwidth*2,fontheight+4,"Send To:",1,256,Localhost_Name {}
  1987.   Else
  1988.     GTString  0,#SERVERBTN,x+serverwidth,y,serverwidth*2,fontheight+4,"Send To:",1,256,"localhost"
  1989.   EndIf
  1990.   GTInteger 0,#PORTBTN,x+(serverwidth*3)+portwidth+3,y,numberswidth,fontheight+4,"Port:",1,#PORT
  1991.   GTButton  0,#BUTTON,331,y,delaywidth,fontheight+4,"Server",$10
  1992.   GTButton  0,63,333+delaywidth,y,disconnectwidth,fontheight+4,"Disconnect",$10
  1993.   y+fontheight+5
  1994.  
  1995.   hostnamey=y
  1996.  
  1997.   GTButton  0,54,5,y,pingwidth,fontheight+4,"Localhost:",$10
  1998.  
  1999.   WinWidth=x+(serverwidth*3)+portwidth+numberswidth+9+3+connectwidth+8+disconnectwidth+8+90
  2000.  
  2001.   y+fontheight+5
  2002.  
  2003.   GTButton  0,55,120,y,firstperson,fontheight+4,"1:",$10
  2004.   GTButton  0,56,180,y,firstperson,fontheight+4,"2:",$10
  2005.   GTButton  0,57,240,y,firstperson,fontheight+4,"3:",$10
  2006.   GTButton  0,58,300,y,firstperson,fontheight+4,"4:",$10
  2007.   GTButton  0,59,360,y,firstperson,fontheight+4,"5:",$10
  2008.   GTButton  0,60,420,y,firstperson,fontheight+4,"6:",$10
  2009.   GTButton  0,61,480,y,firstperson,fontheight+4,"7:",$10
  2010.   GTButton  0,62,540,y,firstperson,fontheight+4,"8:",$10
  2011.   For i= 1To8
  2012.     pingprintx(i)=86+ i*60
  2013.   Next
  2014.   pingprinty=y
  2015.  
  2016.   GTString  0,64,50,215,550,fontheight+4,"Send:",1,67,""
  2017.  
  2018.   WinHeight=y+fontheight+5
  2019.  
  2020.   ;WinX=WBWidth/2-(WinWidth/2)
  2021.   ;WinY=WBHeight/2-(WinHeight/2)
  2022.  
  2023.   WinTitle$="UDP Chat"
  2024.   ;ScreenTitle$="UDP Send "+Chr$(169)+"1997."
  2025.  
  2026.   Window 0,0,10,630,245,$0002|$0004|$0008,WinTitle$,1,2
  2027.   Use Window 0:Activate 0:AttachGTList 0,0:WTitle WinTitle$,ScreenTitle$:Menus Off
  2028.  
  2029.   WindowOutput0
  2030.   WindowInput 0
  2031.  
  2032.   a$=Localhost_Name {}   ;
  2033.   WLocate 5+pingwidth+15,hostnamey+3
  2034.   Print a$
  2035.  
  2036.   WLocate 10,y+3
  2037.   Print"Ping Time-VBL"
  2038.  
  2039.   SetInt 5       ; start VBlank timer- this can't be in a If - Then Clause!
  2040.     If NTSC      ; Set up for a PAL rate
  2041.       If drop_frame=6  ; drop every 6th frame on a NTSC (60fps) system to get a PAL 50 fps rate
  2042.         drop_frame=0
  2043.       Else
  2044.         drop_frame+1
  2045.         system_time.l+1
  2046.       EndIf
  2047.     Else
  2048.       system_time.l+1   ; up the counter every VBL
  2049.     EndIf
  2050.   End SetInt
  2051.  
  2052.   CNIF #COMMS_DEBUG=0
  2053.     If FindPortnnn_(PORT_NAME.s)
  2054.         Exit{"UDP_Chat already running!"}
  2055.     EndIf
  2056.   CEND
  2057.  
  2058.   rexxport.l=CreateMsgPort(PORT_NAME.s)
  2059.   If rexxport=0
  2060.     Exit{"Unable to open Rexxport!"}
  2061.   EndIf
  2062.   rexxmsg.l=CreateRexxMsg(rexxport,"rexx",PORT_NAME.s)
  2063.  
  2064.   Print_String {"Type in data, and hit return to send."}
  2065.  
  2066.   ;********** This is the individual player data ****************
  2067.   ;        these are just examples- they could be anything
  2068.   player_info(0)\info_type=#NUMBERW    ; player's colour
  2069.   player_info(0)\numberw=6
  2070.   player_info(1)\info_type=#NUMBERL    ; Player's score
  2071.   player_info(1)\numberl=55555
  2072.   player_info(2)\info_type=#STRING     ; Player's name
  2073.   player_info(2)\string="Anton Reinauer"
  2074.   player_info(3)\info_type=#STRING     ; Player's nick
  2075.   player_info(3)\string="`Ants"
  2076.   player_info(4)\info_type=#END_OF_CRITICAL_DATA
  2077.   ;*************************************************************
  2078.  
  2079. Return
  2080.  
  2081.  
  2082.